﻿using Microsoft.Extensions.Logging;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
using System.Xml.Linq;
using TrackSystem.Contracts;
using TrackSystem.Entities.Extensions;
using TrackSystem.Entities.Models;
using TrackSystem.IO.Alarm;
using TrackSystem.IO.Formula;
using TrackSystem.IO.Logics;
using TrackSystem.IO.Loops;
using TrackSystem.IO.Ports;
using TrackSystem.IO.Sensors;
using TrackSystem.IO.Utils;

namespace TrackSystem.IO.Data
{
    public class RegFactory
    {

        #region 成员变量定义
        public static RegFactory Instance;

        /// <summary>
        /// 变量字典
        /// </summary>
        [Required]
        public ConcurrentDictionary<string, OperandDef> Regs;

        /// <summary>
        /// 变量属性字典
        /// </summary>
        [Required]
        public ConcurrentDictionary<string, RegDefine> Attrs;

        /// <summary>
        /// 线程句柄
        /// </summary>
        private Thread thd;

        /// <summary>
        /// 运行标志
        /// </summary>
        public bool Running;

        /// <summary>
        /// 实际运行时间
        /// </summary>
        public  int Lapse;

        /// <summary>
        /// 实际运行周期
        /// </summary>
        public  int Cycle;

        /// <summary>
        /// 设定运行周期
        /// </summary>
        public  int Interval = 100;

        /// <summary>
        /// 使能标志
        /// </summary>
        public  bool Enabled = false;
        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        static RegFactory()
        {
            Instance = new RegFactory();
            Instance.Init();
        }

        /// <summary>
        /// 变量初始化
        /// </summary>
        private void Init()
        {
            Regs = new ();
            Attrs = new();
            Enabled = false;
            Running = false;
        }

        public ResultMsg Load(IRepositoryWrapper wrapper)
        {
            Disposable();

            try
            {
                var vars = wrapper.Var.GetAllList();
                var namesDict = vars.Select(a => new { a.Name, a.DataType }).ToDictionary(a => a.Name, b => b.DataType);
                List<VarTable> ordVars = vars.OrderBy(v => v.snrloopIndex).ThenBy(v => v.snrloopId).ToList();

                foreach (var item in ordVars)
                {
                    Regs.TryAdd(item.Name, new OperandDef(item.DataType));
                    if (item.Serial == VarSerialEnum.UserDefine && !item.ReadOnly)
                        Regs[item.Name].SetStringValue(item.InitValue ??= "0");

                    RegDefine attr = new RegDefine
                    {
                        Name = item.Name,
                        Serial = item.Serial,
                        VarType = item.DataType,
                        SnrloopId = item.snrloopId,
                        SnrloopIndex = item.snrloopIndex,
                        ReadOnly = item.ReadOnly,
                        ClacuateFormula = item.ClacuateFormula,
                        IsRecord = item.IsRecord,
                        RecordCycle = item.RecordCycle,
                        AlarmSetting = item.AlarmSetting,
                        HighAlarmSet = new OperandDef(item.HighAlarmSet),
                        LowAlarmSet = new OperandDef(item.LowAlarmSet),
                        exprStack = new Stack<ExprItem>()
                    };

                    // 记录时间以100ms为记录单位，小于100ms按照100ms计算
                    attr.RecordCycle = attr.RecordCycle / 100;
                    if (attr.RecordCycle < 1)
                        attr.RecordCycle = 1;

                    if (item.Serial == VarSerialEnum.UserDefine && item.ReadOnly)
                    {
                        try
                        {
                            var result = ClacuationFormula.PreTreat(item.ClacuateFormula);
                            List<string> lstResult = ClacuationFormula.Segment(result.Message);
                            ClacuationFormula.Parse(lstResult, attr.exprStack, namesDict);
                        }
                        catch (Exception ex)
                        {
                            AlarmFactory.Instance.Insert($"{item.ClacuateFormula}: {ex.Message}", AlarmCategory.REG, item.Name, 0);
                        }
                    }
                    Attrs.TryAdd(item.Name, attr);
                }

                // ------------启动线程----------------------
                thd = new Thread(WorkerThread)
                {
                    IsBackground = true
                };
                Running = true;
                Enabled = true;
                thd.Start();

                return ResultMsg.Succ("初始化寄存器成功");
            }
            catch (Exception ex)
            {
                return ResultMsg.Fail($"初始化寄存器失败, {ex.Message}");
            }
        }

        /// <summary>
        /// 析构函数
        /// </summary>
        public void Disposable()
        {
            Enabled = false;

            if (Running)
            {
                Running = false;
                thd.Join();
            }

            Regs.Clear();
            Attrs.Clear();
            FormulaTools.Instance.Clear();
        }

        /// <summary>
        /// 变量设置新的值
        /// </summary>
        /// <param name="name"></param>
        /// <param name="val"></param>
        public void SetVal(string name, double val)
        {
            if (Regs.ContainsKey(name) && Regs[name].DataType == DataTypeEnum.DOUBLE)
            {
                Regs[name].dVal = val;
            }
        }

        /// <summary>
        /// 变量设置新的值
        /// </summary>
        /// <param name="name"></param>
        /// <param name="val"></param>
        public void SetVal(string name, int val)
        {
            if (Regs.ContainsKey(name))
            {
                if (Regs[name].DataType == DataTypeEnum.DOUBLE)
                    Regs[name].dVal = val;
                if (Regs[name].DataType == DataTypeEnum.INTEGER)
                    Regs[name].iVal = val;
            }
        }

        /// <summary>
        /// 获取当前值
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public OperandDef GetVal(string name)
        {
            if (Regs.TryGetValue(name, out var op))
            {
                return op;
            }

            return new OperandDef();
        }

        /// <summary>
        /// 定义索引器
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public OperandDef this[string name]
        {
            get
            {
                if (Regs.TryGetValue(name, out var op))
                    return op;
                return new OperandDef();
            }
            set
            {
                PushValue(name, value);
            }
        }

        /// <summary>
        /// 工作者线程
        /// </summary>
        private void WorkerThread()
        {
            int startTicks, deltaTicks, temp;
            int lastTicks = Environment.TickCount;
            string name;
            long loopTicks = 0;                // 循环计数器，为数据记录服务

            while (Running)
            {
                // 如果没有使能，则不进行运算
                if (!Enabled)
                {
                    Thread.Sleep(Interval);
                    continue;
                }

                startTicks = Environment.TickCount;
                try
                {
                    foreach (var item in Attrs.Values)
                    {
                        // 获取通道属性 --------------------------------------------
                        if (item.Serial == VarSerialEnum.Attr_Channel  &&
                            PortFactory.Instance.IdNameDictionary.TryGetValue(item.SnrloopId, out name))
                        {
                            Regs[item.Name] = PortFactory.Instance.Items[name].GetVal(item.SnrloopIndex);
                        }

                        // 获取传感器属性  -------------------------------------------
                        if (item.Serial == VarSerialEnum.Attr_Sensor &&
                            SensorFactory.Instance.IdNameDictionary.TryGetValue(item.SnrloopId, out name))
                        {
                            Regs[item.Name] = SensorFactory.Instance.Items[name].GetVal(item.SnrloopIndex);
                        }

                        // 获取逻辑程序属性  -------------------------------------------
                        if (item.Serial == VarSerialEnum.Attr_Logic &&
                            LogicFactory.Instance.IdNameDictionary.TryGetValue(item.SnrloopId, out name))
                        {
                            Regs[item.Name] = LogicFactory.Instance.Items[name].GetVal(item.SnrloopIndex);
                        }

                        // 获取回路属性 --------------------------------------
                        if (item.Serial == VarSerialEnum.Loop &&
                            LoopFactory.Instance.IdNameDictionary.TryGetValue(item.SnrloopId, out name))
                        {
                            Regs[item.Name] = LoopFactory.Instance.Items[name].GetVal(item.SnrloopIndex);
                        }
                        
                        // 计算自定义变量
                        if (item.Serial == VarSerialEnum.UserDefine && item.ReadOnly)
                        {
                            try
                            {
                                // item.Value.LastVal.Assign(item.Value.CurrentVal);
                                if (item.exprStack is not null)
                                    item.CurrentVal = ClacuationFormula.Evaluate(item.exprStack);
                                Regs[item.Name] = item.CurrentVal;
                            }
                            catch (Exception e)
                            {
                                AlarmFactory.Instance.Insert(e.Message, AlarmCategory.REG, item.ClacuateFormula??="", 0);
                            }
                        }
                    }
                }
                catch (Exception)
                {
                }             


                // ------运行时间处理---------------------------------------------
                temp = Environment.TickCount;
                Cycle = temp - lastTicks;
                Lapse = temp - startTicks;
                lastTicks = temp;
                deltaTicks = Interval - Lapse;

                if (deltaTicks > 0)
                    Thread.Sleep(deltaTicks);

                // 循环计数器，为数据记录服务
                loopTicks++;
            }
        }

        /// <summary>
        /// 修改寄存器的值
        /// </summary>
        /// <param name="name"></param>
        /// <param name="op"></param>
        /// <returns></returns>
        public bool PushValue(string name, OperandDef op)
        {
            name = name.Trim();

            // 不存在该变量名称，返回
            if (!Attrs.TryGetValue(name, out var attr))
            {
                return false;
            }

            string partname;

            // 调节回路属性
            if (attr.Serial == VarSerialEnum.Attr_Loop)
            {
                if (LoopFactory.Instance.IdNameDictionary.TryGetValue(attr.SnrloopId, out partname))
                {
                    LoopFactory.Instance.Items[partname].SetVal(attr.SnrloopIndex, op);
                    return true;
                }
            }

            // 如果是只读变量 返回
            if (attr.ReadOnly)
            {
                return false;
            }

            if (attr.Serial == VarSerialEnum.Sensor && SensorFactory.Instance.IdNameDictionary.TryGetValue(attr.SnrloopId, out partname))
            {
                if (op.DataType == DataTypeEnum.DOUBLE)
                {
                    SensorFactory.Instance.Items[partname].PushRegValue(attr.SnrloopIndex, (int)op.dVal);
                }
                else
                {
                    SensorFactory.Instance.Items[partname].PushRegValue(attr.SnrloopIndex, op.iVal);
                }
                return true;
            }

            //自定义变量属性
            if (attr.Serial == VarSerialEnum.UserDefine)
            {
                Regs[name].Assign(op);
                return true;
            }

            // 通道属性 ENABLE
            if (attr.Serial == VarSerialEnum.Attr_Channel && attr.SnrloopIndex == 0)
            {
                if (PortFactory.Instance.IdNameDictionary.TryGetValue(attr.SnrloopId, out var chnname))
                {
                    PortFactory.Instance.Items[chnname].Enabled = op.bVal;
                    return true;
                }
            }

            // 逻辑属性 ENABLE
            if (attr.Serial == VarSerialEnum.Attr_Logic && attr.SnrloopIndex == 0)
            {
                if (LogicFactory.Instance.IdNameDictionary.TryGetValue(attr.SnrloopId, out var logicname))
                {
                    LogicFactory.Instance.Items[logicname].Enabled = op.bVal;
                    return true;
                }
            }

            // 传感器属性 ENABLE
            if (attr.Serial == VarSerialEnum.Attr_Sensor && attr.SnrloopIndex == 0)
            {
                if (SensorFactory.Instance.IdNameDictionary.TryGetValue(attr.SnrloopId, out var snrName))
                {
                    SensorFactory.Instance.Items[snrName].Enabled = op.bVal;
                    return true;
                }
            }

            return false;
        }
    }
}
